/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights
 * reserved. <a>http://www.cqcis.com</a>
 */
package com.firebird.base.utils;

import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 * @author qiuxj
 * @date 2009-11-14
 */
public class IntrospectionUtils {
	
	  public static boolean getProperties(Object target, Map<String, Object> props, String prefix)
	  {
	    boolean rc = false;

	    checkArguments(target, props);

	    if (prefix == null) {
	      prefix = "";
	    }
	    Class clazz = target.getClass();
	    Method[] methods = clazz.getMethods();
	    for (int i = 0; i < methods.length; ++i) {
	      Method method = methods[i];
	      String name = method.getName();
	      Class type = method.getReturnType();
	      Class[] params = method.getParameterTypes();
	      if ((!(name.startsWith("get"))) || (params.length != 0) || (type == null) || (!(isSettableType(type)))) continue;
	      try {
	        Object value = method.invoke(target, new Object[0]);
	        if (value != null)
	        {
	          String strValue = convertToString(value, type);
	          if (strValue != null)
	          {
	            name = name.substring(3, 4).toLowerCase() + name.substring(4);
	            props.put(prefix + name, strValue);
	            rc = true;
	          }
	        }
	      } catch (Throwable localThrowable) {
	      }
	    }
	    return rc;
	  }

	  private static void checkArguments(Object target, Map<String, Object> props) {
	    if (target == null) {
	      throw new IllegalArgumentException("target was null.");
	    }
	    if (props == null)
	      throw new IllegalArgumentException("props was null.");
	  }

	  public static Map<String, Object> getProperties(Object target, String prefix)
	  {
	    Map map = new HashMap();
	    getProperties(target, map, prefix);
	    return map;
	  }

	  public static boolean setProperties(Object target, Map<String, Object> props)
	  {
	    boolean rc = false;

	    checkArguments(target, props);

	    for (Iterator iter = props.entrySet().iterator(); iter.hasNext(); ) {
	      Map.Entry entry = (Map.Entry)iter.next();
	      if (setProperty(target, (String)entry.getKey(), entry.getValue())) {
	        iter.remove();
	        rc = true;
	      }
	    }

	    return rc;
	  }

	  public static boolean setProperties(Object target, Map<String, Object> props, String prefix)
	  {
	    boolean rc = false;

	    checkArguments(target, props);

	    for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
	      String name = (String)iter.next();
	      if (name.startsWith(prefix)) {
	        Object value = props.get(name);
	        name = name.substring(prefix.length());
	        if (setProperty(target, name, value)) {
	          iter.remove();
	          rc = true;
	        }
	      }
	    }
	    return rc;
	  }

	  public static Map<String, Object> extractProperties(Map<String, Object> props, String prefix)
	  {
	    if (props == null) {
	      throw new IllegalArgumentException("props was null.");
	    }
	    HashMap rc = new HashMap(props.size());

	    for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
	      String name = (String)iter.next();
	      if (name.startsWith(prefix)) {
	        Object value = props.get(name);
	        name = name.substring(prefix.length());
	        rc.put(name, value);
	        iter.remove();
	      }
	    }

	    return rc;
	  }

	  public static String simpleName(Class<?> clazz)
	  {
	    String name = clazz.getName();
	    int p = name.lastIndexOf(".");
	    if (p >= 0) {
	      name = name.substring(p + 1);
	    }
	    return name;
	  }

	  public static boolean setProperty(Object target, String name, Object value) {
	    try {
	      Class clazz = target.getClass();
	      Method setter = findSetterMethod(clazz, name);
	      if (setter == null) {
	        return false;
	      }

	      if ((value == null) || (value.getClass() == setter.getParameterTypes()[0])) {
	        setter.invoke(target, new Object[] { value });
	      }
	      else {
	        setter.invoke(target, new Object[] { convert(value, setter.getParameterTypes()[0]) });
	      }
	      return true; } catch (Throwable ignore) {
	    }
	    return false;
	  }

	  private static Object convert(Object value, Class<?> type) throws URISyntaxException
	  {
	    SimpleDateFormat dateFormat = null;
	    PropertyEditor editor = PropertyEditorManager.findEditor(type);
	    if (editor != null) {
	      editor.setAsText(value.toString());
	      return editor.getValue();
	    }
	    if (type == Date.class)
	      dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	    try {
	      return dateFormat.parseObject(value.toString());
	    } catch (ParseException exception) {
	      System.out.println("时间转换异常");

	      if (type == Boolean.class) {
	        return new Boolean(value.toString().trim());
	      }
	      if (type == Integer.class) {
	        return new Integer(value.toString().trim());
	      }
	      if (type == URI.class) {
	        return new URI(value.toString());
	      }
	    }
	    return null;
	  }

	  private static String convertToString(Object value, Class<?> type) throws URISyntaxException {
	    PropertyEditor editor = PropertyEditorManager.findEditor(type);
	    if (editor != null) {
	      editor.setValue(value);
	      return editor.getAsText();
	    }
	    if (type == Boolean.class) {
	      return ((Boolean)value).toString();
	    }
	    if (type == Integer.class) {
	      return ((Integer)value).toString();
	    }
	    if (type == URI.class) {
	      return ((URI)value).toString();
	    }
	    return null;
	  }

	  static Method findSetterMethod(Class<?> clazz, String name)
	  {
	    name = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
	    Method[] methods = clazz.getMethods();
	    for (int i = 0; i < methods.length; ++i) {
	      Method method = methods[i];
	      Class[] params = method.getParameterTypes();
	      if ((method.getName().equalsIgnoreCase(name)) && (params.length == 1) && (isSettableType(params[0]))) {
	        return method;
	      }
	    }
	    return null;
	  }

	  private static boolean isSettableType(Class<?> clazz) {
	    if (PropertyEditorManager.findEditor(clazz) != null) {
	      return true;
	    }
	    if (clazz == Date.class) {
	      return true;
	    }
	    if (clazz == URI.class) {
	      return true;
	    }
	    if (clazz == Boolean.class) {
	      return true;
	    }

	    return (clazz == Integer.class);
	  }

	  public static String toString(Object target)
	  {
	    return toString(target, Object.class);
	  }

	  public static String toString(Object target, Class<?> stopClass) {
	    LinkedHashMap map = new LinkedHashMap();
	    addFields(target, target.getClass(), stopClass, map);
	    StringBuffer buffer = new StringBuffer(simpleName(target.getClass()));
	    buffer.append(" {");
	    boolean first = true;
	    for (Object entry : map.entrySet()) {
	      if (first)
	        first = false;
	      else {
	        buffer.append(", ");
	      }
	      buffer.append((String)((Map.Entry)entry).getKey());
	      buffer.append(" = ");
	      appendToString(buffer, ((Map.Entry)entry).getValue());
	    }
	    buffer.append("}");
	    return buffer.toString();
	  }

	  protected static void appendToString(StringBuffer buffer, Object value) {
	    buffer.append(value);
	  }

	  private static void addFields(Object target, Class<?> startClass, Class<?> stopClass, Map<String, Object> map)
	  {
	    if (startClass != stopClass) {
	      addFields(target, startClass.getSuperclass(), stopClass, map);
	    }

	    Field[] fields = startClass.getDeclaredFields();
	    for (int i = 0; i < fields.length; ++i) {
	      Field field = fields[i];
	      if ((!(Modifier.isStatic(field.getModifiers()))) && (!(Modifier.isTransient(field.getModifiers())))) {
	        if (Modifier.isPrivate(field.getModifiers())) {
	          continue;
	        }
	        try
	        {
	          field.setAccessible(true);
	          Object o = field.get(target);
	          if ((o != null) && (o.getClass().isArray()))
	            try {
	              o = Arrays.asList((Object[])o);
	            }
	            catch (Throwable localThrowable1) {
	            }
	          map.put(field.getName(), o);
	        } catch (Throwable e) {
	          e.printStackTrace();
	        }
	      }
	    }
	  }

}
